package com.zang.jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * 方法区和运行时常量池溢出异常测试
 * 1.6之前可以通过设置 -XX:PermSize=10M -XX:MaxPermSize=10M （方法区大小，常量池是方法区的一部分）来测试，1.6常量池分配在永久代之中。1.6中intern()方法会把首次遇到的字符串实例复制到
 * 永久代之中，返回其实例
 * 1.7之后则不会复制实例，只是在常量池之中记录首次出现的实例引用
 * @author Zhang Qiang
 * @date 2019/12/12 17:11
 */
public class RunTimeConstantPoolOOMAction {

    public static void main(String[] args) {
        //oom();
        buildIntern();
    }

    public static void oom(){
        List<String> list = new ArrayList<>();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
            if (i%999 == 0){
                System.out.println("list :" + list.size());
            }
        }
    }

    /**
     s.intern():
     返回s在常量池中的引用地址。
     * 1.6中是在常量池中复制字符串实例
     * 1.7中是在常量池中复制字符串引用

     String s = new String("1")：
     此时如果常量池中没有1这个字符串则会在常量池创建1字符串，在用new关键字的时候，还会在堆空间中开辟一块内存区域创建1字符串，然后将堆中的对象地址返回赋值给s（即此时栈区会有一个引用s指向堆区的对象）。
     此时 s.intern() 不等于 s

     String s = "1"：
     此时如果常量池中没有1这个字符串则会在常量池中创建1字符串，然后s则是栈区中的引用，指向常量池中字符串1。如果有1则直接创建栈区对象s直接引向常量池中的字符串1。
     此时 s.intern() 等于 s
     */
    public static void buildIntern(){
//        String ii = new StringBuilder("计算机").append("测试").toString();
//        System.out.println("ii.intern() == ii:   " + ( ii.intern() == ii));
//        String i2 = new StringBuilder("疯狂").append("测试").toString();
//        System.out.println("i2.intern() == i2:   " + (i2.intern() == i2));
//
//        String s3 = new String("1") + new String("1");
//        String intern = s3.intern();
//        System.out.println("s3==intern:   " + (s3==intern));
//
//        String s4 = new String("y") + new String("t");
//        String intern4 = s4.intern();
//        System.out.println("s4==intern:   " + (s4==intern4));

        String s = new String("1");//生成常量池中的1，（new关键字）在堆空间中开辟一块内存区域，在其中存放字符串1。
        System.out.println(s == s.intern());//常量池中有1, s是指向堆空间的1的引用，s.intern()是指向常量池的1的引用
        String s2 = "1";//常量池中有1，生成s2这个对象引向常量池中的1
        System.out.println(s == s2);
        System.out.println(s.intern() == s2);

        String s3 = new String("1") + new String("1");//常量池中没有11，在堆中创建11，s3引向堆中的11
        //String s3 = new String("11");
        System.out.println(s3.intern() == s3);//常量池中创建11的引用,s3引向常量池中的11的引用
        String s4 = "11";//常量池中有11，s4引向常量池中的11的引用
        System.out.println(s3==s4);//s3==s4


    }

}
